package visualcbir;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.Observable;
import visualcbir.node.IViewNode;
import visualcbir.node.ViewNode;

/**
 *
 * @author sheila
 * Using design pattern Composite.
 */
public abstract class ViewComposed extends View{
    private ArrayList<View> aoViews;
    protected int iNumSubviews;

    public ViewComposed(ModelComposed poModel, int piNumSubviews){
        super(poModel);
        aoViews = new ArrayList<View>();
        this.iNumSubviews = (piNumSubviews< ((ModelComposed)oModel).getNumModels())? piNumSubviews:((ModelComposed)oModel).getNumModels();
        this.makeViewFactory();
    }

    @Override
    public void makeViewFactory(){
        System.out.println("*******  ViewComposed. MAKEVIEWFACTORY com numero de modelos: "+ ((ModelComposed)oModel).getNumModels() + "  - e numero de vistas:"+this.iNumSubviews);
        this.oIBackStructureView = this.makeBackStructureView();
        for (int i = 0; i < ((ModelComposed)oModel).getNumModels() && i<this.iNumSubviews; i++){
            this.addView( ((ModelComposed)oModel).getModel(i)  );// crio uma vista (pode ser no ou vista de vistas)
        }
        System.out.println("*******    MAKE VIEW FACTORY this.getNumViews();"+this.getNumViews());
    }

    public void addView(View oView){   this.aoViews.add(oView);  }
    public abstract void addView(Model oModel);
    
    @Override
    public void clearView(){
           for (int i = 0; i < aoViews.size(); i++) {
            this.aoViews.get(i).clearView();
            this.aoViews.clear();
        }
    }
    
    @Override
    public void update (Observable o, Object arg) {//revisar ao final se da update en todos os niveis
        double scaling = 0.41;// IMPORTANTE este fator afeta o tamanho de todos os subclusters nas estruturas compostas
        for (int i = 0; i < this.getNumViews(); i++){
            if(this.getView(i) instanceof ViewComposed){
                this.getView(i).setScaleFactor(scaling-=0.025);
                this.getView(i).update(o, arg);
            }
        }
    }

    @Override
    public void drawViewFactory(Object pArg){
        Graphics g=(Graphics)pArg;
        if(oIBackStructureView != null) // For views without backstructure (ex. grid)
            oIBackStructureView.drawBackStructure(g);
        //***********************************************
        int red=245, redChange=4;
        int green=240, greenChange=5;
        int blue=40, blueChange=1;

        for (int i = 0; i <this.getNumViews(); i++){ //oModel.getNumModels()
            red-=redChange; if (i>25) redChange=4;
            green-=greenChange;
            blue-=blueChange;
            try {
                Color viewColor = new Color(red,green,blue);
                if(this.getView(i) instanceof ViewNode)
                    ((ViewNode)this.getView(i)).setColor(viewColor);
            } catch (Exception e) {
                  System.out.println("red - gren - blue "+ red+" - "+green+ " - "+blue);
            }            
        }

        System.out.println("this.aoViews.size()"+this.aoViews.size());
        for (int i = 0; i < this.getNumViews() && i<this.iNumSubviews; i++) { //i < this.getNumViews()
            this.aoViews.get(i).drawViewFactory(pArg);
        }
    }

    @Override
    public Dimension computeViewDimension(){
        update(null,null);
        return this.getViewDimension();
    }
 
    //** Methods get and set**//
    public View getView(int i){   return this.aoViews.get(i);   }
    public int getNumViews(){    return this.aoViews.size();    }


    @Override
    public IViewNode getCenterNode() {
        return this.getView(0).getCenterNode();
    }

    public View getMaxSizeSubView(){
        int maxHeight=0;
        View maxSizeView = null;
        for(View v: this.aoViews){
            int currHeight = v.getViewDimension().height;
            if(currHeight > maxHeight){
                maxHeight = currHeight;
                maxSizeView = v;
            }
        }
        return maxSizeView;
    }


    //Nao funcionaba o getCenterPoint porque o center point e relativo da dimensao relativa da vista..
    //Um cluster 'e uma vista pequena e o ponto central esta dentro da dimensao relativa
    public ViewNode findNode(int x, int y){
        //System.out.println("**************************find node");
        View oNearestView=null;int guardarindice = -1;
        double bestDist=Double.MAX_VALUE, dist;
        //System.out.println(" numero de vistas: "+this.getNumViews());
        for (int i = 0; i < this.getNumViews(); i++)// calculate the nearest view
        {
            View currentView=this.aoViews.get(i);
            //if(currentView instanceof ViewComposed)// depois hOW
                dist = Math.pow((currentView.getCenterNode().getCenterPoint().x - x), 2) + Math.pow((currentView.getCenterNode().getCenterPoint().y - y), 2);
            //else
            //    dist = Math.pow((currentView.getCenterPoint().x - x), 2) + Math.pow((currentView.getCenterPoint().y - y), 2);
            //System.out.println("dist>"+dist);
          //calcula el cuadrado de la distancia entre el centro de c/nodo y el punto donde se hizo click
            if ( dist < bestDist  ) {//&& dist<3000
                bestDist=dist;
                oNearestView = getView(i);
                guardarindice=i;
            }
            //System.out.println("vista con x:"+getView(i).getCenterPoint().x + " and y:"+getView(i).getCenterPoint().y + " -  disttancia>"+dist);
            /// adicionar  if(aoViews.get(i) instanceof ViewNode && dist<2500 )
        }
        //System.out.println("la vista mas proxima es: "+guardarindice + "con dist:"+bestDist + "con x:"+oNearestView.getCenterPoint().x + " and y:"+oNearestView.getCenterPoint().x);
        if( oNearestView instanceof ViewComposed){
            //System.out.println("--nearestview instance of view composed");
            oNearestView = ((ViewComposed)oNearestView).findNode(x,y);
        }
        else if(oNearestView instanceof ViewNode && bestDist>1550){
            oNearestView = null;
            //System.out.println("--nearest view mair que 2500");
        }
        return (ViewNode) oNearestView;
    }
//    public ArrayList findCluster(int x, int y){
//        View oNearestView=null;int guardarindice = -1;
//        double bestDist=Double.MAX_VALUE, dist;
//
//        for (int i = 0; i < this.getNumViews(); i++)// calculate the nearest view
//        {
//            View currentView=this.aoViews.get(i);
//            dist = Math.pow((currentView.getCenterNode().getCenterPoint().x - x), 2) + Math.pow((currentView.getCenterNode().getCenterPoint().y - y), 2);
//
//            if ( dist < bestDist  ) {//&& dist<3000
//                bestDist=dist;
//                oNearestView = getView(i);
//                guardarindice=i;
//            }
//        }
//
//        if( oNearestView instanceof ViewComposed){
//            ArrayList aDataUnits = ((ModelComposed)this.oModel).getClusters().get(guardarindice).getaDataUnits();
//            return aDataUnits;
//        }
//        else
//        return null;
//
//
//    }

     
}
